﻿#include "DlgBookRead.h"
#include "ui_DlgBookRead.h"
#include "ui_DlgContents.h"
#include "DlgContents.h"
#include <QColorDialog>
#include <QLoggingCategory>
#include <QTextLayout>
#include <QTextBlock>
#include <QMessageBox>
#include <QScrollBar>
#include <QDesktopWidget>
#include <QBrush>
#include <QRect>
#include "MainWindow.h"
#include "QTextEditSlide.h"
#include <QTextEdit>
#include <QKeyEvent>
#include <locale>
#include <thread>
#include <ctime>
#include <ratio>
#include <chrono>
#include <fstream>
#include <filesystem>
#include <iomanip>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>

using namespace std;

DlgBookRead::DlgBookRead(QWidget* parent) :
	DlgCustom(parent),
	m_threadCacheBook(this),
	ui(new Ui::DlgBookRead),
	m_dlgContents(this),
	m_dlgSearchString(this)
{
	ui->setupUi(this);

	setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);

	ui->frameSet->hide();
	if (ui->frameSet->isVisible())
	{
		on_btnMenu_clicked();
	}

	ui->textEdit->setCursorWidth(100);
	//ui->btnPrevPage->hide();
	//ui->btnNextPage->hide();
	//ui->cbKeepScreenOn->hide();
	connect(ui->textEdit, SIGNAL(on_sig_clicked()), this, SLOT(on_textEdit_clicked()));

	//读取配置记录文件
	int value = g_set->value("book_read/background-color", 0xffc8c8c8).toInt();
	QColor colorBg(value);
	if (colorBg.isValid())
	{
		QColor colorText(colorBg.value() < 50 ? QColor(200, 200, 200) : QColor(0, 0, 0));
		QString strStyleSheet = QString("color: %1;"
			"background-color: %2;").arg(colorText.name()).arg(colorBg.name());
		ui->textEdit->setStyleSheet(strStyleSheet);
	}

	QString strFont = g_set->value("global/font_family", font().family()).toString();
	int iTextSize = g_set->value("global/font_size", TEXT_SIZE_DEFAULT).toInt();
	ui->cbTextSize->setCurrentText(QString::asprintf("%d", iTextSize));// (QString::asprintf("%d", iTextSize));
	ui->fontComboBox->setCurrentText(strFont);
	QFont font = ui->textEdit->font();
	font.setPointSize(iTextSize);
	font.setFamily(strFont);
	ui->textEdit->setFont(font);

	initTTS();
	//connect(ui->pushButtonSpeak,SIGNAL(clicked(bool)),this,SLOT(speak()));
	connect(ui->SliderByPitch, SIGNAL(valueChanged(int)), (QDialog*)this, SLOT(setPitch(int)));
	connect(ui->SliderByRate, SIGNAL(valueChanged(int)), (QDialog*)this, SLOT(setRate(int)));
	connect(ui->SliderByVolume, SIGNAL(valueChanged(int)), (QDialog*)this, SLOT(setVolume(int)));
	connect(ui->cbEngine, SIGNAL(currentIndexChanged(int)), this, SLOT(engineSelected(int)));

	connect(this, &DlgBookRead::on_sig_refresh_finish, this, &DlgBookRead::on_slots_refresh_finish);
	connect(&m_dlgColor, &QColorDialog::colorSelected, this, &DlgBookRead::on_slots_colorSelected);
}

DlgBookRead::~DlgBookRead()
{
	if (m_speech)
	{
		m_speech->stop();
		delete m_speech;
		m_speech = nullptr;
	}
	delete ui;
	ui = nullptr;
}

void DlgBookRead::reject()
{
	stop();
	if (m_threadCacheBook.isRunning())
	{
		m_threadCacheBook.stop();
	}
	if (m_dlgSearchString.m_threadQueryBookString.joinable())
	{
		m_dlgSearchString.m_threadQueryBookStringStop = true;
		m_dlgSearchString.m_threadQueryBookString.join();
	}
	//m_dlgSearchString.m_threadQueryBookString.join();
	//子线程要弹窗提示，弹窗必须在主线程响应消息，故这里不能等待，否则会卡死
	// 子线程中去掉了直接弹窗消息
	/// wait时，子线程中不能弹窗消息，否则会冲突卡死
	m_threadCacheBook.wait(WAIT_THREAD_EXIT_TIME);

	m_dlgContents.ListWidgetClear();
	//搜索窗口清理
	m_dlgSearchString.ListWidgetClear();
	((MainWindow*)parent())->updateListWidgetBook();
	hide();
}

void DlgBookRead::on_btnSetBackgroundColor_clicked()
{
	//m_dlgColor.setWindowIconText(tr("颜色对话框"));
	int value = g_set->value("book_read/background-color", 0xffc8c8c8).toInt();
	m_dlgColor.setCurrentColor(value);
	m_dlgColor.show();
	if (m_dlgColor.frameGeometry().width() > frameGeometry().width()
		|| m_dlgColor.frameGeometry().height() > frameGeometry().height())
	{
		m_dlgColor.move(frameGeometry().width() - m_dlgColor.frameGeometry().width(),
			frameGeometry().height() - m_dlgColor.frameGeometry().height());
	}
	return;
}

void DlgBookRead::on_slots_colorSelected(const QColor& color)
{
	QColor colorBg = color;
	if (colorBg.isValid())
	{
		QColor colorText(colorBg.value() < 50 ? QColor(200, 200, 200) : QColor(0, 0, 0));
		QString strStyleSheet = QString("color: %1;"
			"background-color: %2;").arg(colorText.name()).arg(colorBg.name());
		ui->textEdit->setStyleSheet(strStyleSheet);
		QRgb uiRgba = colorBg.rgba();
		g_set->setValue("book_read/background-color", uiRgba);
	}
}

void DlgBookRead::on_btnContents_clicked()
{
	m_dlgContents.show();
	m_dlgContents.UpdateContents();
}

void DlgBookRead::initTTS()
{
	QLoggingCategory::setFilterRules(QStringLiteral("qt.speech.tts=true \n qt.speech.tts.*=true"));

	ui->SliderByRate->setValue(g_set->value("book_read/rate", 0).toInt());
	ui->SliderByPitch->setValue(g_set->value("book_read/pitch", 0).toInt());
	int volume = g_set->value("book_read/volume", 100).toInt();
	ui->SliderByVolume->setValue(volume);

	//ui->cbEngine->addItem("Default", QString("default"));
	ui->cbEngine->clear();
	QStringList strList = QTextToSpeech::availableEngines();
	for (QString& engine : strList)
		ui->cbEngine->addItem(engine, engine);
	if (strList.size() == 0)
		ui->cbEngine->addItem("default", "default");
	QString strEngine = g_set->value("book_read/engine", "default").toString();
	int index = 0;
	if ((index = strList.indexOf(strEngine)) == -1)
	{
		index = 0;
	}
	ui->cbEngine->setCurrentIndex(index);
	engineSelected(index);
}

void DlgBookRead::play()
{
	if (m_playState == Stop)
		return;

	m_playState = Play;//避免章头重复朗读
	QTextDocument* doc = ui->textEdit->document(); //文本对象
	QTextBlock textLine = doc->findBlockByNumber(m_listBookInfo[0].pos); // 文本中的一段
	QString str = textLine.text();
	if (FindChar(str))
	{
		//移动光标到行
		MoveCursorToLine();
		//朗读
		m_speech->say(str);
		//LOG_DEBUG("m_speech->say: %s", str.left(8).toUtf8().data());
	}
	else
	{
		PlayNextBlock();
	}
}

void DlgBookRead::stop()
{
	m_playState = Stop;
	ui->btnPlay->setText(tr("播放"));
	QIcon aIcon;
	aIcon.addFile(QStringLiteral(":/assets/images/play.png"));
	ui->btnPlay->setIcon(aIcon);
	m_speech->stop();
	ui->comboBoxTimer->setCurrentIndex(0);
}

void DlgBookRead::replay()
{
	if (m_playState != Stop)
	{
		m_playState = PlayCur;
		if (m_speech->state() == QTextToSpeech::Speaking)
			m_speech->stop();
	}
}

void DlgBookRead::on_btnPlay_clicked()
{
	if (m_playState == Stop)
	{
		m_playState = Play;
		ui->btnPlay->setText(tr("暂停"));
		QIcon aIcon;
		aIcon.addFile(QStringLiteral(":/assets/images/stop.png"));
		ui->btnPlay->setIcon(aIcon);
		ui->comboBoxTimer->setCurrentIndex(0);

		QTextDocument* doc = ui->textEdit->document(); //文本对象
		int cnt = doc->blockCount();//回车符是一个 block
		if (m_listBookInfo[0].pos >= cnt)
		{
			m_listBookInfo[0].pos = 0;
			m_listBookInfo[0].SaveChapterInfo();
		}
		if (cnt > 0 && m_listBookInfo[0].pos < cnt)
		{
			play();
		}
	}
	else
	{
		if (m_speech->state() != QTextToSpeech::Speaking)
			initTTS();
		stop();
	}
}

#if 0
//获取一个block 的折叠行数
static void getTextLineCount(QTextBlock& block, int& lineCount)
{
	QTextLayout* lay = block.layout();
	if (block.position() == 0)
	{
		lineCount += lay->lineCount();
		return;
	}
	else
	{
		lineCount += lay->lineCount();
		QTextBlock prev = block.previous();
		if (prev.isValid())
		{
			getTextLineCount(prev, lineCount);
		}
	}
}
#endif

void DlgBookRead::MoveCursorToLine()
{
	if (!g_bAndroidForegroundRunning)
		return;

	int line = m_listBookInfo[0].pos;
	QTextBlock block = ui->textEdit->document()->findBlockByNumber(line);
	QTextCursor textCursor(block);
	int start = block.position();
	int end = start + block.length() - 1;
	textCursor.setPosition(start, QTextCursor::MoveAnchor);
	ui->textEdit->setTextCursor(textCursor);
	QRect rt_cursor = ui->textEdit->cursorRect();
	textCursor.setPosition(end, QTextCursor::KeepAnchor);
	ui->textEdit->setTextCursor(textCursor);

	QRect rtTextEdit = ui->textEdit->rect();
	QSizeF size_document = ui->textEdit->document()->size();
	int value = ui->textEdit->verticalScrollBar()->value();
	if (value >= size_document.height())
		return;
	if (rt_cursor.y() > rtTextEdit.height() / 2)
	{
		value += rt_cursor.y() - rtTextEdit.height() / 2;
	}
	else if (rt_cursor.y() == 0)
	{	// 当光标跑到屏幕上面时需要再次精准定位
		ui->textEdit->verticalScrollBar()->setValue(0);
		rt_cursor = ui->textEdit->cursorRect();
		if (rt_cursor.y() > rtTextEdit.height() / 2)
		{
			value = rt_cursor.y() - rtTextEdit.height() / 2;
		}
	}
	ui->textEdit->verticalScrollBar()->setValue(value);
	return;
}

void DlgBookRead::on_textEdit_clicked()
{
	if (ui->frameSet->isVisible())
	{
		on_btnMenu_clicked();
		return;
	}
	int x = ui->textEdit->m_point.x();
	int width = ui->textEdit->geometry().width();
	if (x > width - width / 5)
	{
		on_btnNextPage_clicked();
	}
	else if (x < width / 5)
	{
		on_btnPrevPage_clicked();
	}
	else
	{
		QTextCursor cursor = ui->textEdit->cursorForPosition(ui->textEdit->m_point);
		int blockNumber = cursor.blockNumber(); //相同tc.block().blockNumber();
		//选中某一段文本
		//此时光标所在的位置
		//选中从start到end的这一段文本
		int start = cursor.block().position();
		int end = start + cursor.block().length() - 1;
		cursor.setPosition(start, QTextCursor::MoveAnchor);
		cursor.setPosition(end, QTextCursor::KeepAnchor);
		ui->textEdit->setTextCursor(cursor);

		if (blockNumber != m_listBookInfo[0].pos)
		{
			m_listBookInfo[0].pos = blockNumber;
			m_listBookInfo[0].SaveChapterInfo();
		}
		replay();
	}
}

void DlgBookRead::engineSelected(int index)
{
	QString str = ui->cbEngine->currentText();
	g_set->setValue("book_read/engine", str);
	QString engineName = ui->cbEngine->itemData(index).toString();
	delete m_speech;
	if (engineName == "default")
		m_speech = new QTextToSpeech(nullptr);
	else
		m_speech = new QTextToSpeech(engineName, nullptr);

	disconnect(ui->cbLanguage, SIGNAL(currentIndexChanged(int)), this, SLOT(languageSelected(int)));
	ui->cbLanguage->clear();

	// Populate the languages combobox before connecting its signal.
	QVector<QLocale> locales = m_speech->availableLocales();
	QLocale current = m_speech->locale();
	foreach(const QLocale & locale, locales) {
		QString name(QString("%1 (%2)")
			.arg(QLocale::languageToString(locale.language()))
			.arg(QLocale::countryToString(locale.country())));
		QVariant localeVariant(locale);
		ui->cbLanguage->addItem(name, localeVariant);
		if (locale.name() == current.name())
			current = locale;
	}

	//QString qstr = g_set->value("book_read/language", "").toString();
	//ui->cbLanguage->setCurrentText(qstr);
	//m_speech->setLocale(QLocale(qstr));

	setRate(ui->SliderByRate->value());
	setPitch(ui->SliderByPitch->value());
	setVolume(ui->SliderByVolume->value());
	connect(m_speech, SIGNAL(stateChanged(QTextToSpeech::State)), (QDialog*)this, SLOT(stateChanged(QTextToSpeech::State)), Qt::DirectConnection);
	connect(m_speech, SIGNAL(localeChanged(QLocale)), (QDialog*)this, SLOT(localeChanged(QLocale)));
	connect(ui->cbLanguage, SIGNAL(currentIndexChanged(int)), this, SLOT(languageSelected(int)));
	localeChanged(current);
}

void DlgBookRead::languageSelected(int cbLanguage)
{
	QLocale locale = ui->cbLanguage->itemData(cbLanguage).toLocale();
	m_speech->setLocale(locale);
	//g_set->setValue("book_read/language", ui->cbLanguage->itemText(cbLanguage));
}

void DlgBookRead::voiceSelected(int index)
{
	m_speech->setVoice(m_voices.at(index));
}

void DlgBookRead::localeChanged(const QLocale& locale)
{
	QVariant localeVariant(locale);
	ui->cbLanguage->setCurrentIndex(ui->cbLanguage->findData(localeVariant));
	QDialog::disconnect(ui->cbVoice, SIGNAL(currentIndexChanged(int)), (QDialog*)this, SLOT(voiceSelected(int)));
	ui->cbVoice->clear();
	m_voices = m_speech->availableVoices();
	QVoice currentVoice = m_speech->voice();
	for (const QVoice& voice : m_voices)
	{
		QString&& str = QString("%1 - %2 - %3").arg(voice.name())
			.arg(QVoice::genderName(voice.gender()))
			.arg(QVoice::ageName(voice.age()));
		ui->cbVoice->addItem(str);
		if (voice.name() == currentVoice.name())
			ui->cbVoice->setCurrentIndex(ui->cbVoice->count() - 1);
	}
	connect(ui->cbVoice, SIGNAL(currentIndexChanged(int)), (QDialog*)this, SLOT(voiceSelected(int)));
	stop();
}

void DlgBookRead::setPitch(int pitch)
{
	m_speech->setPitch(pitch / 10.0);//设置音高-1.0到1.0
	g_set->setValue("book_read/pitch", pitch);
}

void DlgBookRead::setRate(int rate)
{
	m_speech->setRate(rate / 10.0);//设置语速-1.0到1.0
	g_set->setValue("book_read/rate", rate);
}

void DlgBookRead::setVolume(int volume)
{
	m_speech->setVolume(volume / 100.0);//设置音量0.0-1.0
	g_set->setValue("book_read/volume", volume);
}

void DlgBookRead::PlayNextBlock()
{
	QTextDocument* doc = ui->textEdit->document(); //文本对象
	auto cnt = doc->blockCount();//回车符是一个 block
	if (cnt > 0)
	{
		if (m_listBookInfo[0].pos + 1 < cnt)
		{
			m_listBookInfo[0].pos++;
			play();
			m_listBookInfo[0].SaveChapterInfo();
		}
		else
		{
			auto pos = m_listBookInfo[0].pos;
			auto chapter = m_listBookInfo[0].chapter;
			on_btnNext_clicked();
			if (pos != m_listBookInfo[0].pos || chapter != m_listBookInfo[0].chapter)
			{
				play();
			}
		}
	}
}

//查找非符号的字符
bool DlgBookRead::FindChar(QString& str)
{
	for (auto& qchar : str)
	{
		if (qchar.isLetterOrNumber() || qchar.isMark())
		{
			return true;
		}
	}
	return false;
}

void DlgBookRead::stateChanged(QTextToSpeech::State state)
{
	//LOG_DEBUG("old state=%d, new state=%d, m_playState=%d\n", m_stateTTS, state, m_playState);
	m_stateTTS = state;
	if (state == QTextToSpeech::Ready)
	{
		if (m_playState == Play)
		{
			PlayNextBlock();
		}
		else if (m_playState == PlayCur)
		{
			m_playState = Play;
			play();
		}
	}
}

int DlgBookRead::FindChapterTail(const QString& text, const int start)
{
	int i = start;
	int ChapterTailIndex = i;
	int weight = 0;//权重
	int ChineseNumbers = 0;
	i = text.indexOf('\n', i);
	if (i == -1)
		return text.size() - 1;
	if (i > start)
		i--;
	for (; i < text.size(); i++)
	{
		auto value = text[i].unicode();
		if (value == 0x000a)
		{
			if (i >= start + CHAPTER_MAX_LEN)//当章节长度超过CHAPTER_MAX_LEN,开始切分新章节
			{
				for (; i + 1 < text.size(); )
				{
					value = text[i + 1].unicode();
					if (!(value == L' ' ||
						value == L'\t' ||
						value == L'\r' ||
						value == L'\n'))
						break;
					i++;
				}
				return i;
			}
			ChapterTailIndex = i;
			ChineseNumbers = 0;
			weight = 0;
		}
		else
		{
			switch (value)
			{
			case 0x0020://' '
			case 0x0009://'\t'
				continue;
			case 0xa1a1://不可见字符
			case 0x3000:
				continue;
			}

			switch (value)
			{
			case 0x7b2c://第
				weight += 1;
				break;
				//0123456789
			case 0x0030:
			case 0x0031:
			case 0x0032:
			case 0x0033:
			case 0x0034:
			case 0x0035:
			case 0x0036:
			case 0x0037:
			case 0x0038:
			case 0x0039:
				weight += 1;
				break;
				//一两二三四五六七八九零十百千万亿
			case 0x4e00:
			case 0x4e24:
			case 0x4e8c:
			case 0x4e09:
			case 0x56db:
			case 0x4e94:
			case 0x516d:
			case 0x4e03:
			case 0x516b:
			case 0x4e5d:
			case 0x96f6:
			case 0x5341:
			case 0x767e:
			case 0x5343:
			case 0x4e07:
			case 0x4ebf:
				ChineseNumbers = 1;
				break;
			case 0x5377://卷
			case 0x7ae0://章
				weight += 2;
				break;

			default:
				i = text.indexOf('\n', i);
				if (i == -1)
					return text.size() - 1;
				i--;
				continue;
			}
			if (weight + ChineseNumbers > 2)
				return ChapterTailIndex;
		}
	}
	return text.size() - 1;
}

int DlgBookRead::ParseFile()
{
	if (m_listBookInfo.size() <= 0)
		return -2;
	m_chapterList.clear();
	string strFilePath = m_listBookInfo[0].path.toLocal8Bit().data();
	std::ifstream ifs(strFilePath, std::ios::binary);
	if (!ifs)
	{
		QMessageBox::StandardButton btnSelect;
		btnSelect = QMessageBox::warning(this, tr("警告"), m_listBookInfo[0].path
			+ tr("\n打开文件失败!是否删除本书?"), QMessageBox::Yes | QMessageBox::No);
		if (btnSelect == QMessageBox::Yes)
		{
			return -1;
		}
		else
		{
			return 1;
		}
		return -1;
	}
	else
	{
		std::ostringstream oss;
		oss << ifs.rdbuf();
		auto&& str = oss.str();
		int nFileLen = (int)str.size();
		if (nFileLen > 0)
		{
			QString strText;
			string strCharset = GetCharset(str);
			if (strCharset == "utf-8")
			{
				strText = QString::fromStdString(str.c_str());
			}
			else
			{
				strText = ToUnicode(str.c_str(), strCharset.c_str());
			}

			nFileLen = strText.size();
			int indexHead = 0;
			int indexTail = 0;
			while (1)
			{
				indexTail = FindChapterTail(strText, indexHead);
				auto&& text = strText.mid(indexHead, indexTail - indexHead);
				auto index = text.indexOf('\n');
				auto&& head = text.left(index);
				text = text.right(text.length() - index - 1);
				m_chapterList.emplace_back(text, head);
				if (indexTail + 1 >= nFileLen)
					break;
				indexHead = indexTail + 1;
			}
		}
	}
	if (m_chapterList.size() == 0)
	{
		QMessageBox::StandardButton btnSelect;
		btnSelect = QMessageBox::warning(this, tr("警告"), m_listBookInfo[0].path
			+ tr("\n获取本书章节列表失败!是否删除本书?"), QMessageBox::Yes | QMessageBox::No);
		if (btnSelect == QMessageBox::Yes)
		{
			return -1;
		}
		else
		{
			return 2;
		}
	}

	if (m_listBookInfo[0].chapter >= m_chapterList.size())
		m_listBookInfo[0].chapter = 0;
	m_listBookInfo[0].maxChapter = (int)m_chapterList.size();
	return 0;
}

void DlgBookRead::UpdateChapter()
{
	int index = 0;
	if (m_chapterList.size() <= 0)
		return;
	if (m_chapterList.size() <= m_listBookInfo[0].chapter + 1)//最后一章
	{
		index = (int)m_chapterList.size() - 1;
		if (m_listBookInfo[0].chapter != index)//防止读文件获取的章节位置超限
		{
			m_listBookInfo[0].chapter = index;
			m_listBookInfo[0].pos = 0;
		}
	}
	else
	{
		index = m_listBookInfo[0].chapter;
	}

	m_listBookInfo[0].strChapterHead = m_chapterList[index].head;
	SaveBookListInfo();
	if (m_listBookInfo[0].IsWeb())//网书
	{
	GET_WEB_INFO:
		int iRet = ThreadCacheBook::GetChapterText(m_listBookInfo[0], m_chapterList[index], true);
		if (iRet >= 0) //字符数少时也算正常
		{
			goto UPDATE_CHAPTER_END;
		}
		else
		{
			QMessageBox::StandardButton btnSelect;
			btnSelect = QMessageBox::warning(this, tr("警告"), m_listBookInfo[0].path + "\n" + m_listBookInfo[0].strChapterHead
				+ tr("\n获取章节内容失败!是否重试?"), QMessageBox::Yes | QMessageBox::No);
			if (btnSelect == QMessageBox::Yes)
			{
				goto GET_WEB_INFO;
			}
			else
			{
				stop();
				goto UPDATE_CHAPTER_END;
			}
		}
	}
	else
	{
	UPDATE_CHAPTER_END:
		//if (m_bNextChapter)
		//{
		//	const int iSearchLen = 100;
		//	auto strCurSub = m_strListChapter[index].mid(m_strListChapter[index].indexOf('\n'), iSearchLen);
		//	DeleteSymbol(strCurSub);
		//	//判断前面几章节是否有相同的,有重复就跳过
		//	for (int i = 1; i <= 4; i++)
		//	{
		//		if (index - i >= 0 && strCurSub.length() > 0
		//			&& m_strListChapter[index - i].length() > iSearchLen)
		//		{
		//			auto strOld = m_strListChapter[index - i].mid(m_strListChapter[index - i].indexOf('\n'), iSearchLen);
		//			DeleteSymbol(strOld);
		//			if (strOld.indexOf(strCurSub) != -1)
		//			{
		//				on_btnNext_clicked();
		//				return;
		//			}
		//		}
		//	}
		//}
		ui->textEdit->setText(m_chapterList[index].GetHeadAndText());
		//移动光标到行
		MoveCursorToLine();
		m_listBookInfo[0].SaveChapterInfo();
		replay();
		//SaveBookListInfo();
	}
}

void DlgBookRead::on_btnPrev_clicked()
{
	if (m_listBookInfo[0].chapter > 0)
	{
		m_bNextChapter = false;
		m_listBookInfo[0].chapter--;
		m_listBookInfo[0].pos = 0;
		UpdateChapter();
	}
}

void DlgBookRead::on_btnNext_clicked()
{
	if (m_listBookInfo[0].chapter + 1 < m_chapterList.size())
	{
		m_bNextChapter = true;
		m_listBookInfo[0].chapter++;
		m_listBookInfo[0].pos = 0;
		UpdateChapter();
	}
	else if (m_listBookInfo[0].IsWeb())
	{
		string list_ini;
		list_ini = list_ini + BOOK_LIST_SAVE_DIR"cache/" + m_listBookInfo[0].name.toLocal8Bit().data() + "/list.ini";
		//需要C++17以上
		//auto ftime = std::chrono::duration_cast<std::chrono::seconds>(
		//	std::filesystem::last_write_time(list_ini).time_since_epoch()).count();
		//auto cur_ftime = std::chrono::duration_cast<std::chrono::seconds>(
		//	std::filesystem::file_time_type::clock::now().time_since_epoch()).count();

		struct stat file_state;
		int ret = 0;
		memset(&file_state, 0x00, sizeof(file_state));
		ret = stat(list_ini.c_str(), &file_state);
		//判断ini文件状态获取失败，或者一天内没有更新过
		if (ret != 0 || time(NULL) - file_state.st_mtime > 60 * 60 * 24)
		{
		GET_CONTENTS_LIST:
			int iRet = ThreadCacheBook::GetChapterList(m_listBookInfo[0], m_chapterList, true);
			if (iRet >= 0 && m_chapterList.size() > 0)
			{
				on_btnNext_clicked();
			}
			else
			{
				QMessageBox::StandardButton btnSelect;
				btnSelect = QMessageBox::warning(this, tr("警告"), m_listBookInfo[0].name + "\n" + m_listBookInfo[0].path
					+ tr("\n获取章节列表失败!是否重试?"), QMessageBox::Yes | QMessageBox::No);
				if (btnSelect == QMessageBox::Yes)
				{
					goto GET_CONTENTS_LIST;
				}
				else
				{
					stop();
				}
			}
		}
		else
		{
			goto END;
		}
	}
	else
	{
	END:
		stop();
		QMessageBox::StandardButton btnSelect;
		btnSelect = QMessageBox::information(this, m_listBookInfo[0].name, tr("\n章节完毕!") + "\n" + m_listBookInfo[0].path);
	}
}

void DlgBookRead::on_btnPrevPage_clicked()
{
	QScrollBar* verticalScrollBar = ui->textEdit->verticalScrollBar();
	if (verticalScrollBar->value() <= 0)
	{
		int chapterOld = m_listBookInfo[0].chapter;
		on_btnPrev_clicked();
		if (chapterOld != m_listBookInfo[0].chapter)
		{
			// 必须这么麻烦，不然不能到最底下
			int maximum = verticalScrollBar->maximum();
			verticalScrollBar->setMaximum(maximum << 1);
			maximum = verticalScrollBar->maximum();
			verticalScrollBar->setValue(maximum);
		}
		return;
	}

	QRect rt = ui->textEdit->rect();
	int row = 0;
	int lineSpacing = ui->textEdit->fontMetrics().lineSpacing();//leading()+height()
	row = rt.bottom() / lineSpacing;
	int value = verticalScrollBar->value();
	value -= (row - 1) * lineSpacing;
	value = value / lineSpacing * lineSpacing;
	verticalScrollBar->setValue(value);
}

void DlgBookRead::on_btnNextPage_clicked()
{
	QScrollBar* verticalScrollBar = ui->textEdit->verticalScrollBar();
	int value = verticalScrollBar->value();
	int maximum = verticalScrollBar->maximum();
	if (value == maximum)
	{
		on_btnNext_clicked();
		return;
	}

	QRect rt = ui->textEdit->rect();
	int row = 0;
	int lineSpacing = ui->textEdit->fontMetrics().lineSpacing();//leading()+height()
	row = rt.bottom() / lineSpacing;
	value += row * lineSpacing;
	value = value / lineSpacing * lineSpacing;
	verticalScrollBar->setValue(value);
}

void DlgBookRead::on_cbTextSize_currentTextChanged(QString str)
{
	int size = str.toInt();
	g_set->setValue("global/font_size", size);
	if (isVisible())
		((MainWindow*)parent())->setGlobalFont();
}

void DlgBookRead::on_fontComboBox_currentTextChanged(QString strFont)
{
	g_set->setValue("global/font_family", strFont);
	if (isVisible())
		((MainWindow*)parent())->setGlobalFont();
}

void DlgBookRead::on_btnMenu_clicked()
{
	if (ui->frameSet->isVisible())
	{
		ui->frameSet->hide();
		ui->btnMenu->setText(tr("菜单"));
		QIcon aIcon;
		aIcon.addFile(QStringLiteral(":/assets/images/menu.png"));
		ui->btnMenu->setIcon(aIcon);
	}
	else
	{
		ui->frameSet->show();
		ui->btnMenu->setText(tr("隐藏"));
		QIcon aIcon;
		aIcon.addFile(QStringLiteral(":/assets/images/shrink.png"));
		ui->btnMenu->setIcon(aIcon);
	}
}

void DlgBookRead::on_comboBoxTimer_currentIndexChanged(const QString& strTime)
{
	if (m_nTimerID != 0)
	{
		killTimer(m_nTimerID);
		m_nTimerID = 0;
	}
	const int iMinute = 60000;
	if (strTime.length() < 2 || strTime[0] == '0')
		return;

	int num = 0;
	for (auto wc : strTime)
	{
		ushort us = wc.unicode();
		if (us >= '0' && us <= '9')
		{
			num = (us - '0') + num * 10;
		}
	}
	if (strTime.indexOf("分钟") != -1)
	{
		m_nTimerID = startTimer(num * iMinute);
	}
	else if (strTime.indexOf("小时") != -1)
	{
		m_nTimerID = startTimer(num * 60 * iMinute);
	}
}

void DlgBookRead::timerEvent(QTimerEvent* event)
{
	if (event->timerId() == m_nTimerID)
	{
		if (m_nTimerID != 0)
		{
			killTimer(m_nTimerID);
			m_nTimerID = 0;
			ui->comboBoxTimer->setCurrentIndex(0);
		}
		if (m_playState)
			on_btnPlay_clicked();
	}
}

void DlgBookRead::on_btnCacheWebBook_clicked()
{
	if (m_listBookInfo[0].IsWeb())
	{
		if (ui->btnCacheWebBook->text().indexOf(BUTTON_IN_PROGRESS) != -1)
		{
			m_threadCacheBook.stop();
		}
		else if (!m_threadCacheBook.isRunning())
		{
			ui->btnCacheWebBook->setText(ui->btnCacheWebBook->text() + BUTTON_IN_PROGRESS);
			m_threadCacheBook.start();
		}
	}
}

void DlgBookRead::on_slots_cache_finish()
{
	ui->btnCacheWebBook->setText("缓存");
	QString dlgTitle = tr("缓存报告");
	QMessageBox::information(this, dlgTitle, msg_cache_finish, QMessageBox::Ok, QMessageBox::NoButton);
}

void DlgBookRead::on_slots_refresh_finish(bool b)
{
	if (b)
	{
		ui->textEdit->setText(m_chapterList[m_listBookInfo[0].chapter].GetHeadAndText());
		//移动光标到行
		MoveCursorToLine();
		replay();
	}
	else
	{
		QMessageBox::StandardButton btnSelect;
		btnSelect = QMessageBox::warning(this, tr("警告"), m_listBookInfo[0].path + "\n"
			+ m_listBookInfo[0].strChapterHead
			+ tr("\n刷新本章节内容失败! 是否重试?"), QMessageBox::Yes | QMessageBox::No);
		if (btnSelect == QMessageBox::Yes)
		{
			on_btnRefreshCurChapter_clicked();
		}
		else
		{
			stop();
		}
	}
}

void DlgBookRead::on_btnRefreshCurChapter_clicked()
{
	if (m_listBookInfo[0].IsWeb() && ui->btnRefreshCurChapter->text().indexOf(BUTTON_IN_PROGRESS) == -1)
	{
		std::thread([&]
			{
				QString strSrc = ui->btnRefreshCurChapter->text();
				ui->btnRefreshCurChapter->setText(strSrc + BUTTON_IN_PROGRESS);
				QString strPath = m_listBookInfo[0].path;
				int chapter = m_listBookInfo[0].chapter;

				int iRet = ThreadCacheBook::GetChapterText(m_listBookInfo[0], m_chapterList[m_listBookInfo[0].chapter], false, true);
				if (iRet >= 0 && strPath == m_listBookInfo[0].path && chapter == m_listBookInfo[0].chapter)
				{
					emit on_sig_refresh_finish(true);
				}
				else
				{
					emit on_sig_refresh_finish(false);
				}
				ui->btnRefreshCurChapter->setText(strSrc);
			}).detach();
	}
}

void DlgBookRead::on_btnSearchString_clicked()
{
	m_dlgSearchString.exec();
}

void DlgBookRead::on_btnClearCache_clicked()
{
	static std::thread s_thread;
	static auto stop = true;

	auto run = [&]()
		{
			stop = false;
			QString del_file = QString(BOOK_LIST_SAVE_DIR"cache") + "/" + m_listBookInfo[0].name;
			string strPath = del_file.toLocal8Bit().data();
			QString strBtnText = ui->btnClearCache->text();
			ui->btnClearCache->setText(strBtnText + BUTTON_IN_PROGRESS);
			DelSuffixFile(strPath, "chapter", stop, 5);
			ui->btnClearCache->setText(strBtnText);
		};

	if (s_thread.joinable()) {
		stop = true;
		s_thread.join();
	}
	else
	{
		s_thread = std::thread(run);
		s_thread.detach();
	}
}

